package com.intretech.umsin.oss.util;

import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Item;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @version V1.0
 * @ClassName: MinioUtil
 * @Description: MinioUtil 服务实现
 * @author: 李启联
 * @date: 2022-04-25 16:40
 * @Copyright: Copyright (c) 2022
 */

public class MinioUtil {

    private String  endpoint;// MINIO服务所在地址
    private String  bucketName;//#存储桶名称
    private String  accessKey;// #访问KEY
    private String  secretKey;// #访问秘钥
    private Integer signedUrlExpires; //对象临时授权链接失效时间(单位为秒)

    private MinioClient ninioclient;

    public MinioUtil(String endpoint, String bucketName, String accessKey, String secretKey, Integer signedUrlExpires) throws Exception{
        this.endpoint = endpoint;
        this.bucketName = bucketName;
        this.accessKey = accessKey;
        this.secretKey = secretKey;
        this.signedUrlExpires = signedUrlExpires;

        ninioclient = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
        // 判断桶是否存在
        boolean isExist = ninioclient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        if (!isExist) {
            // 新建桶
            ninioclient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 桶占位符
     */
    private static final String BUCKET_PARAM = "${bucket}";
    /**
     * bucket权限-只读
     */
    private static final String READ_ONLY = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetObject\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";
    /**
     * bucket权限-只写
     */
    private static final String WRITE_ONLY = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";
    /**
     * bucket权限-读写
     */
    private static final String READ_WRITE = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";

    /**
     * 文件url前半段
     *
     * @param bucket 桶
     * @return 前半段
     */
    public String getObjectPrefixUrl(String bucket) {
        return String.format("%s/%s/", endpoint, bucket);
    }

    public String getObjectPrefixUrl() {
        return String.format("%s/%s/", endpoint, bucketName);
    }


    /**
     * 创建桶
     *
     * @param bucket 桶
     */
    public void makeBucket(String bucket) throws Exception {
        // 判断桶是否存在
        boolean isExist = ninioclient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
        if (!isExist) {
            // 新建桶
            ninioclient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
        }
    }

    /**
     * @param bucket
     * @throws Exception
     */
    public void removeBucket(String bucket) throws Exception {
        ninioclient.removeBucket(RemoveBucketArgs.builder().bucket(bucket).build());
    }

    /**
     * 更新桶权限策略
     *
     * @param bucket 桶
     * @param policy 权限
     */
    public void setBucketPolicy(String bucket, String policy) throws Exception {
        switch (policy) {
            case "read-only":
                ninioclient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).config(READ_ONLY.replace(BUCKET_PARAM, bucket)).build());
                break;
            case "write-only":
                ninioclient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).config(WRITE_ONLY.replace(BUCKET_PARAM, bucket)).build());
                break;
            case "read-write":
                ninioclient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).config(READ_WRITE.replace(BUCKET_PARAM, bucket)).build());
                break;
            case "none":
            default:
                break;
        }
    }

    /**
     * 列出一个桶中的所有文件和目录
     */
    public List<Item> listObjects(String bucket) throws Exception {
        Iterable<Result<Item>> results = ninioclient.listObjects(
                ListObjectsArgs.builder().bucket(bucket).recursive(true).build());
        List<Item> infos = new ArrayList<>();
        for (Result<Item> result : results) {
            infos.add(result.get());
        }
        ;
        return infos;
    }

    /**
     * 上传本地文件
     *
     * @param bucket    桶
     * @param objectKey 文件key
     * @param filePath  文件路径
     * @return 文件url
     */
    public String uploadFile(String bucket, String objectKey, String filePath) throws Exception {
        ninioclient.uploadObject(UploadObjectArgs.builder().bucket(bucket).object(objectKey).filename(filePath).contentType("image/png").build());
        return getObjectPrefixUrl(bucket) + objectKey;
    }

    /**
     * 流式上传文件
     *
     * @param bucket      桶
     * @param objectKey   文件key
     * @param inputStream 文件输入流
     * @return 文件url
     */
    public String uploadInputStream(String bucket, String objectKey, InputStream inputStream) throws Exception {
        ninioclient.putObject(PutObjectArgs.builder().bucket(bucket).object(objectKey).stream(inputStream, inputStream.available(), -1).build());
        return getObjectPrefixUrl(bucket) + objectKey;
    }

    /**
     * 流式上传文件
     *
     * @param objectKey   文件key
     * @param inputStream 文件输入流
     * @return 文件url
     * @throws Exception
     */
    public String uploadInputStream(String objectKey, InputStream inputStream) throws Exception {
        ninioclient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectKey).stream(inputStream, inputStream.available(), -1).build());
        return getObjectPrefixUrl() + objectKey;
    }

    /**
     * 创建文件夹或者目录
     *
     * @param objectKey
     * @return
     * @throws Exception
     */
    public String createEmptyFolder(String objectKey) throws Exception {
        ninioclient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectKey).stream(new ByteArrayInputStream(new byte[]{}), 0, -1).build());
        return getObjectPrefixUrl() + objectKey;
    }

    /**
     * 下载文件
     *
     * @param bucket    桶
     * @param objectKey 文件key
     * @return 文件流
     */
    public InputStream download(String bucket, String objectKey) throws Exception {
        return ninioclient.getObject(GetObjectArgs.builder().bucket(bucket).object(objectKey).build());
    }

    /**
     * 下载文件
     *
     * @param objectKey 文件key
     * @return 文件流
     * @throws Exception
     */
    public InputStream download(String objectKey) throws Exception {
        return ninioclient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectKey).build());
    }

    /**
     * 文件复制
     *
     * @param sourceBucket    源桶
     * @param sourceObjectKey 源文件key
     * @param bucket          桶
     * @param objectKey       文件key
     * @return 新文件url
     */
    public String copyFile(String sourceBucket, String sourceObjectKey, String bucket, String objectKey) throws Exception {
        CopySource source = CopySource.builder().bucket(sourceBucket).object(sourceObjectKey).build();
        ninioclient.copyObject(CopyObjectArgs.builder().bucket(bucket).object(objectKey).source(source).build());
        return getObjectPrefixUrl(bucket) + objectKey;
    }

    /**
     * 删除文件
     *
     * @param bucket    桶
     * @param objectKey 文件key
     */
    public void deleteFile(String bucket, String objectKey) throws Exception {
        ninioclient.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectKey).build());
    }

    /**
     * 删除文件
     *
     * @param objectKey 文件key
     * @throws Exception
     */
    public void deleteFile(String objectKey) throws Exception {
        ninioclient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectKey).build());
    }

    /**
     * 获取文件签名url
     *
     * @param bucket    桶
     * @param objectKey 文件key
     * @param expires   签名有效时间  单位秒
     * @return 文件签名地址
     */
    public String getSignedUrl(String bucket, String objectKey, int expires) throws Exception {
        return ninioclient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucket).object(objectKey).expiry(expires).build());
    }

    /**
     * 获取文件签名url
     *
     * @param objectKey
     * @return
     * @throws Exception
     */
    public String getSignedUrl(String objectKey) {
        try {
            return ninioclient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(objectKey).expiry(signedUrlExpires).build());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


}
